/**********************项目描述**********************/

/**
 *  Mao语言运行器
 *
 *  main.c
 *
 *  @author jslidong
 *
 *  @version 1.0.1
 */

/**********************项目要求**********************/

/*
 
 Mao 语言运行器
 个人项目:编写一个程序能够运行 Mao 语言代码。
 要求：以命令行第一个参数为 Mao 语言源代码路径,读取并执行该源代码,结果在屏幕上输出即可。
 
 1.基本介绍
 Mao 语言中只有两类变量——32 位有符号整数 “int” 和 64 位有符号浮点数 “double”
 变量名只包含英文字母和数字,并且第一个字符不能是数字
 常量也只会是这两类中的一 种,当常量中含有小数点 “.” 时才会被认为是浮点数,例如,3 是整数而 3.0 是浮点数。
 在 Mao 语言中,浮点数不会使用科学记数表示法(如 1e-8 等)。
 一个 Mao 语言程序包含许多行代码,每一行只有一个以分号结尾的语句。
 Mao 语言中最多有两个部分——变量定义部分和 语句执行部分。
 
 2.变量定义部分
    每个 Mao 语言程序的开头都可能会是变量定义部分,该部分包含若干的变量定义语句,
    而变量的定义如 C 语言中一样,如 “int a;”、“double b, c;”,
    Mao 语 言中的变量定义不能初始化,所有的变量的初始值都为 0,
    Mao 语言规定变量名不能 超过 20 个字符。
 
 3. 语句执行部分
    紧接着变量定义部分(如果存在)的就是语句执行部分了,语句执行部分的每一条语句或者是个表达式或者就是一个输出语句。
    输出语句的形式如 “print(x);”,该语句会单独 一行输出 x(x 是变量或者常量)。
    如果要输出的是浮点数类型则需要保留 6 位小数,Mao 语言不允许以 “print” 为变量名,即 “print” 为 Mao 语言的保留关键字。
    Mao 语言中的表达式语法及优先级基本和 C 语言相同,但是 Mao 语言的操作符更少:
    操作符 
    左括号      (
    右括号      )
    赋值        =
    加         +
    减         -
    乘         *
    除         /
 
    需要强调的是隐式转换,同 C 语言中一样,一个整数同一个浮点数进行运算的话,整 数会被隐式转为浮点型。
    而当一个浮点数赋值给一个整型变量时,它的小数部分会丢失。
 
 4.运行时错误
    在 Mao 语言中,只会出现一种运行时的错误——除 0,
    当除法运算的右运算符的值为0 时会触发该错误,运行器需要输出单独一行“divided by ZERO”并且结束程序的运行。
 
 5.示例
    源代码:
        int a;
        double x, y; int b, c, d; a=5.5; x=y=(1+a)*6.44; a+4;
        a=a/2; print(a); y=(c+6)*-(1+1); print(y); d=a/(2/5); print(d);
    运行结果:
        2
        -12.000000
        divided by ZERO
 
 6. 说明
    Mao 语言中的常量指的是字面常量如 3 和 3.0 等,并不存在特殊的常量修饰符
    语句中可能会出现一些不影响程序语义的空格,如 “a = b*c;”
 在本项目中不需要考虑溢出的问题
 
 */

/**********************待实现部分**********************/

/*
 1.栈链表相关方法 get
 2.文件读取与处理
 3.中缀式转后缀式 get
 4.逆波兰式计算结果
 5.其他方法
*/

/**********************预编译**********************/

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#define true 1
#define false 0
#define fP "/Users/lidong/C/MaoIde/FinalProject/示例/D1.mao"
#define structSize sizeof(struct variableList)
    //变量链表中一个变量的大小
#define objectSize sizeof(struct object)
    //栈内一个数据结构体的大小

/**********************结构体定义**********************/

/**
 *  栈
 */
struct object
{
    char* element;
    struct object* previous;
};
    //对象结构体(链表为“栈”)

/**
 *  变量链表
 */
struct variableList
{
    char type;
    char* variableName;
    /**
     *  共同体，用于记录整数值或浮点值
     */
    union
    {
        int intVaule;
        double doubleVaule;
    }variableValue;
    struct variableList* next;
}variable;
    //变量链表，仅有一个，名为vaeiable

/**********************全局变量**********************/

struct variableList* variableListHead = NULL;
    //用于存放链表头的变量链表结构体指针变量，初始化值为空.

/**********************变量链表方法声明**********************/

void initVariableList(char* variableName,char type,...);
    //初始化变量链表方法
void emptyVariableList();
    //清空变量链表方法
int isEmptyVariableList();
    //判断空变量链表方法
void addNode(char* variableName,char type,...);
    //在变量链表末尾添加节点方法
void dealLastNode();
    //删除变量链表末尾节点方法
struct variableList* getLastNode();
    //得到变量链表最后节点方法
void delVariableListNode(int nodeIndex);
    //删除变量链表指定节点方法
void insertVariableListNode(int nodeIndex,char* variableName,char type,...);
    //插入变量链表指定节点方法
struct variableList* getVariableListNode(int nodeIndex);
    //得到变量链表指定节点方法
int getNodeNumber();
    //计算变量链表节点数方法
struct variableList* searchVariable(char* variableName);
    //搜索链表链表中指定变量方法

/**********************栈方法声明**********************/

void initStack(struct object** stackHead);
    //初始化栈方法
void emptyStack(struct object* stackHead);
    //清空栈方法
int isEmptyStack(struct object* stackHead);
    //判断空栈方法
void pushStack(struct object** stackHead,char* element);
    //压栈方法
struct object* popStack(struct object** stackHead);
    //弹栈方法
void reverStack(struct object** stackHead);
    //反转栈方法
char* getTop(struct object* stackHead);
    //得到栈顶元素方法

/**********************其他方法声明**********************/

FILE * getFile();
    //得到文件指针方法
struct object* getRpn (struct object** lnfixStack);
    //得到逆波兰式方法
int judgeElemnt(char* element);
    //判断元素方法
int judgeOperators(char* waittedOperator,char* StackOperator);
    //是否可压入操作符栈判断方法

/**********************主函数**********************/

int main(int argc, const char * argv[]) {
    FILE* file = getFile();
    /*char* c;
    struct object* stack;
    pushStack(&stack, "s");
    pushStack(&stack, "b");
    reverStack(&stack);
    c = popStack(&stack)->element;
    printf("%s",c);
    printf("%s",getTop(stack));
    char* element = ")3";
    printf("%d",judgeElemnt(element));
     *///测试反转栈方法
    /*
    struct object* Stack = NULL;
    pushStack(&Stack, "5");
    pushStack(&Stack, "+");
    pushStack(&Stack, "(");
    pushStack(&Stack, "(");
    pushStack(&Stack, "1");
    pushStack(&Stack, "+");
    pushStack(&Stack, "2");
    pushStack(&Stack, ")");
    pushStack(&Stack, "*");
    pushStack(&Stack, "4");
    pushStack(&Stack, ")");
    pushStack(&Stack, "-");
    pushStack(&Stack, "3");
    reverStack(&Stack);
    struct object* resultStack = getRpn(&Stack);
    reverStack(&resultStack);
    while (!isEmptyStack(resultStack)) {
        printf("%s ",popStack(&resultStack)->element);
    }
    printf("\n");
    *///测试逆波兰式转换方法
}

/**********************变量链表方法实现**********************/

/**
 初始化变量变量链表
 
 - returns: 空
 */
void initVariableList(char* variableName,char type,...)
{
    va_list arg_ptr;
    struct variableList* firstNode;
    firstNode = (struct variableList*)malloc(structSize);
    va_start(arg_ptr, type);
    if (type == 'i') {
        firstNode->variableValue.intVaule = va_arg(arg_ptr, int);
    }else{
        firstNode->variableValue.doubleVaule = va_arg(arg_ptr, double);
    }
    firstNode->type = type;
    firstNode->variableName = variableName;
    firstNode->next = NULL;
    variableListHead = firstNode;
}//初始化变量链表方法

/**
 *  置空变量链表
 */
void emptyVariableList()
{
    variableListHead = NULL;
}//清空变量链表方法

/**
 *  判断变量链表是否为空
 *
 *  @return 是/否
 */
int isEmptyVariableList()
{
    return variableListHead==NULL?true:false;
}//判断空变量链表方法

/**
 *  在变量链表最后添加一个节点方法
 *
 *  @param variableName 变量名
 *  @param type         变量类型
 *  @param ...          变量值
 */
void addNode(char* variableName,char type,...)
{
    va_list arg_ptr;
    struct variableList* lastNode;
    struct variableList* nextNode;
    va_start(arg_ptr, type);
    if (isEmptyVariableList()) {
        if (type == 'i') {
            initVariableList(variableName, type,va_arg(arg_ptr, int));
        }
        else{
            initVariableList(variableName, type,va_arg(arg_ptr, double));
        }
    }
    else {
        lastNode = getLastNode();
        nextNode = (struct variableList*)malloc(structSize);
        lastNode->next = nextNode;
        nextNode->variableName = variableName;
        nextNode->type = type;
        if (type == 'i') {
            nextNode->variableValue.intVaule = va_arg(arg_ptr, int);
        }else {
            nextNode->variableValue.doubleVaule = va_arg(arg_ptr, double);
        }
    }
    
}//在变量链表末尾添加节点方法

/**
 *  删除变量链表最后一个节点方法
 */
void dealLastNode(){
    struct variableList* lastNode = variableListHead;
    while (NULL != lastNode->next->next ) {
        lastNode = lastNode->next;
    }
    lastNode->next = NULL;
}//删除变量链表末尾节点方法

/**
 *  得到变量链表最后一个节点方法
 *
 *  @return 链表最后一个节点
 */
struct variableList* getLastNode(){
    struct variableList* LastNode = variableListHead;
    for (int i = 1; i < getNodeNumber(); i++) {
        LastNode = LastNode->next;
    }
    return LastNode;
}//得到变量链表最后节点方法

/**
 *  删除变量链表指定节点方法
 *
 *  @param nodeIndex 待删除节点索引
 */
void delVariableListNode(int nodeIndex){
    struct variableList* dealNode = variableListHead;
    struct variableList* previousNode = NULL;
    if (nodeIndex == 1) {
        variableListHead = dealNode->next;
        return;
    }
    for (int i = 1; i < nodeIndex; i++) {
        if (i == nodeIndex-1) {
            previousNode = dealNode;
        }
        dealNode = dealNode->next;
    }
    if (dealNode->next == NULL) {
        previousNode->next = NULL;
    }
    previousNode->next = dealNode->next;
}//删除变量链表指定节点方法

/**
 *  在变量链表指定位置处插入节点
 *
 *  @param nodeIndex    指定位置
 *  @param variableName 变量名
 *  @param type         变量类型
 *  @param ...          变量值
 */
void insertVariableListNode(int nodeIndex,char* variableName,char type,...){
    va_list arg_ptr;
    va_start(arg_ptr, type);
    struct variableList* inseartedNode = (struct variableList*)malloc(structSize);
    struct variableList* previousNode = variableListHead;
    struct variableList* nextNode;
    for (int i = 1; i < nodeIndex-1; i++) {
        previousNode = previousNode->next;
    }
    nextNode = previousNode->next;
    previousNode->next = inseartedNode;
    inseartedNode->next = nextNode;
    inseartedNode->variableName = variableName;
    inseartedNode->type = type;
    if (type == 'i') {
        initVariableList(variableName, type,va_arg(arg_ptr, int));
    }
    else{
        initVariableList(variableName, type,va_arg(arg_ptr, double));
    }
}//插入变量链表指定节点方法

/**
 *  得到变量链表指定节点方法
 *
 *  @param nodeIndex 指定节点索引
 *
 *  @return 链表指定节点
 */
struct variableList* getVariableListNode(int nodeIndex){
    struct variableList* wantedNode = variableListHead;
    for (int i = 1; i < nodeIndex; i++) {
        wantedNode = wantedNode->next;
    }
    return wantedNode;
}//得到变量链表指定节点方法

/**
 *  计算变量链表节点个数方法
 *
 *  @return 链表节点个数
 */
int getNodeNumber(){
    int i = 1;
    if (isEmptyVariableList()) {
        return 0;
    }
    struct variableList* tempNode = variableListHead;
    while (NULL != tempNode->next) {
        i++;
        tempNode = tempNode->next;
    }
    return i;
}//计算变量链表节点数方法

/**
 *  在变量链表中按指定变量名搜索变量
 *
 *  @param variableName 指定变量名
 *
 *  @return 想要的变量，包含变量名，类型，数值（未找到则返回NULL）
 */
struct variableList* searchVariable(char* variableName){
    struct variableList* wantedVariable = variableListHead;
    while (NULL != wantedVariable->next ) {
        if(strcmp(variableName, wantedVariable->variableName)){
            return wantedVariable;
        }else {
            wantedVariable = wantedVariable->next;
        }
    }
    return NULL;
}//搜索链表链表中指定变量方法

/***********************栈方法实现**********************/

/**
 *  初始化栈
 *
 *  @return 一个指向一个空栈的栈结构体指针
 *
 */
void initStack(struct object** stackHead)
{
    *stackHead = NULL;
}//初始化栈方法

/**
 *  清空栈
 *
 *  @param stackHead 指向栈的顶部数据的指针
 */
void emptyStack(struct object* stackHead)
{
    stackHead = NULL;
}//清空栈方法

/**
 *  判断栈是否为空
 *
 *  @param stackHead 指向栈的顶部数据的指针
 *
 *  @return 是或(1或0)
 */
int isEmptyStack(struct object* stackHead)
{
    return stackHead==NULL?true:false;
}//判断空栈方法

/**
 *  压栈
 *
 *  @param stackHead 指向栈的顶部数据的指针
 *  @param element   压栈数据的元素
 */
void pushStack(struct object** stackHead,char* element)
{
    struct object* top = (struct object*)malloc(objectSize);
    top->previous = *stackHead;
    top->element = element;
    *stackHead = top;
}//压栈方法

/**
 *  弹栈
 *
 *  @param objectHead 指向栈顶部数据的指针的指针
 *
 *  @return 栈顶部的数据
 */
struct object* popStack(struct object** stackHead)
{
    struct object* lastObject = *stackHead;
    *stackHead = lastObject->previous;
    return lastObject;
}//弹栈方法

/**
 *  反转栈
 *
 *  @param stackHead 指向待反转的栈的栈顶的指针
 *
 *  @return 指向反转后的栈的指针
 */
void reverStack(struct object** stackHead)
{
    struct object* reveredStack = NULL;
    while (!isEmptyStack(*stackHead)) {
        pushStack(&reveredStack, popStack(stackHead)->element);
    }if (reveredStack != NULL) {
        *stackHead = reveredStack;
    }
    
}//反转栈方法

/**
 *  得到栈顶元素
 *
 *  @param stackHead 给定栈
 *
 *  @return 字符指针
 */
char* getTop(struct object* stackHead)
{
    if (isEmptyStack(stackHead)) {
        return NULL;
    }
    return stackHead->element;
}//得到栈顶元素方法

/***********************其他方法实现**********************/

/**
 *  得到指定文件指针方法
 *
 *  @return 按指定路径得到的文件指针
 */
FILE * getFile(){
    //char* filePath = (char*)malloc(50*sizeof(char));
    //scanf("%s",filePath);
    return fopen(fP, "r");
}//得到文件指针方法

/**
 *  得到逆波兰式
 *
 *  @param lnfixStack 前缀表达式栈
 *
 *  @return 转换后的逆波兰式
 */
struct object* getRpn (struct object** lnfixStack)
{
    struct object* operatorsStack = NULL;
    struct object* resultStack = NULL;
    while (!isEmptyStack(*lnfixStack)) {//当还有记号可以读取时
        char* element = popStack(lnfixStack)->element;//读取一个记号
        int elementType = judgeElemnt(element);
        switch (elementType) {
            case 0:{
                pushStack(&resultStack, element);//记号为数字时将其压入结果栈
                break;
            }
            case 1:{
                if (!isEmptyStack(operatorsStack)) {//如果记号为操作符，且操作符栈不为空
                    while(!judgeOperators(element, getTop(operatorsStack))){
                        if (isEmptyStack(operatorsStack)) {
                            break;
                        }
                        //循环至该记号比操作符栈栈顶操作符优先级高
                        pushStack(&resultStack, popStack(&operatorsStack)->element);
                        //将操作符栈中操作符弹出至结果栈
                    }
                }
                pushStack(&operatorsStack, element);//将该操作符压入操作符栈
                break;
            }
            case 2:{
               if (*element == '(') {//如果记号为左括号
                    pushStack(&operatorsStack, element);//将其压入操作符栈中
                }else{
                    while (*getTop(operatorsStack) != '(') {
                        pushStack(&resultStack, popStack(&operatorsStack)->element);
                        //当操作符栈顶不为左括号时循环弹出操作符栈中操作符并将其压入结果栈
                    }
                    popStack(&operatorsStack);
                    //弹出左括号
                }
                break;
            }
            default:
                break;
        }

    }
    while (!isEmptyStack(operatorsStack)) {
        pushStack(&resultStack, popStack(&operatorsStack)->element);
    }//无记号可读时将操作符栈中元素全部弹出并压入结果栈
    return resultStack;
}//转换逆波兰式方法

/**
 *  判断元素（字符串所代表类型）
 *
 *  @param element 待判断字符串
 *
 *  @return 0为数字1为运算符2位左右括号3为变量名
 */
int judgeElemnt(char* element)
{
    char c = *element;
    if (c>='0'&&c<='9') {
        return 0;
    }else if (c=='+'|c=='-'|c=='*'|c=='/'){
        return 1;
    }else if(c=='('|c==')'){
        return 2;
    }else{
        return 3;
    }
}//元素判断方法

/**
 *  通过操作符优先级判断是否可压入操作符栈
 *
 *  @param waittedOperator 待判断操作符
 *  @param StackOperator   操作符栈顶操作符
 *
 *  @return 1可压入操作符栈0不可压入操作符栈
 */
int judgeOperators(char* waittedOperator,char* StackOperator)
{
    if (StackOperator == NULL) {
        return 1;
    }
    if (*StackOperator == '(') {
        return 1;
    }
    if (*StackOperator == '*' ||*StackOperator == '/') {
        return 0;
    }else {
        if (*waittedOperator == '+'||*waittedOperator=='-') {
            return 0;
        }else{
            return 1;
        }
    }
}//是否可压入操作符栈判断方法

/***********************版权信息**********************/

/*
 MaoIde->main.c
 Created by 李栋 on 15/12/21.
 Copyright © 2015年 李栋. All rights reserved.
*/

/***********************参考资料**********************/

/*
 调度场算法          http://t.cn/R4bXBUe
 逆波兰式表示法       http://t.cn/R4bX1WJ
 运算符优先级         http://t.cn/R4bX3tT
 */

/***********************项目结语**********************/

/*

*/

/***********************项目结束**********************/